﻿using Jayden.Dll.Web.HtmlControls;

namespace Jayden.Dll.Web.Controls
{
	public class MandelbrotSetDiv : Div
	{
		private MandelbrotSetCanvas m_MandelbrotSet;
		private Span m_Position;
		private Input m_Reset;

		public override void Load(System.Xml.XmlNode node, HtmlControlLoader loader)
		{
			base.Load(node, loader);

			m_MandelbrotSet = GetElementByServerId<MandelbrotSetCanvas>("mandelbrotSet", true);
			m_Reset = GetElementByServerId<Input>("reset", true);
			m_Position = GetElementByServerId<Span>("position", true);
		}

		public override void ProcessJsRequest(HttpHandlerContext context)
		{
			base.ProcessJsRequest(context);

			context.Js[GetType().FullName].AppendOnInit(@"
	var $reset = $('#" + m_Reset.Id + @"');
	var $canvas = $('#" + m_MandelbrotSet.Id + @"');
	var $position = $('#" + m_Position.Id + @"');
	$canvas.data('positionchange', function(pos) {
		$position.text('(' +pos.x + ';' + pos.y + ')');
	});
	$reset.click(function() {
		$canvas.data('resetViewport')();
	});
");
		}
	}
	public class MandelbrotSetCanvas : Canvas
	{
		public override void Load(System.Xml.XmlNode node, HtmlControlLoader loader)
		{
			base.Load(node, loader);
			if (Id == null)
				Id = "mandelbrotSet";
		}

		public override void ProcessJsRequest(HttpHandlerContext context)
		{
			base.ProcessJsRequest(context);

			context.Js[Id].AppendOnInit(@"
	var getIterations = function(cx, cy, max) {
		var ix = 0;
		var iy = 0;
		var iter = 0;
		var sqIx = 0;
		var sqIy = 0;
		var tmp;
		while( (sqIx + sqIy) < 4 && iter < max) {
			tmp = sqIx - sqIy + cx;
			iy = 2 * ix * iy + cy;
			ix = tmp;
			sqIx = ix * ix;
			sqIy = iy * iy;
			iter++;
		}
		return iter;
	};

	var setPixel = function(imageData, x, y, r, g, b, a) {
		var index = (x + y * imageData.width) * 4;
		imageData.data[index+0] = r;
		imageData.data[index+1] = g;
		imageData.data[index+2] = b;
		imageData.data[index+3] = a;
	};

	var $canvas = $('#" + Id + @"');
	var $zoner = $('<div style=""position:absolute;display:none;"" class=""mandelbrot zone""></div>');

	$canvas.parent().append($zoner);

	var canvas = $canvas[0];
	var c = canvas.getContext('2d');
	var width = canvas.width;
	var height = canvas.height;

	var viewport = { x: -3, y: -1, width: 4, height: 2 };

	var ratio = width / height;

	var mousedownOfs = null;
	$canvas.mousedown(function(e) {
		mousedownOfs = {left: e.pageX, top: e.pageY};
		$zoner.show().offset({left: e.pageX, top: e.pageY}).width(1).height(1);
		$('body').addClass('noselect');
		$(window).mousemove(mousemoveFunc).mouseup(mouseupFunc);
	}).mousemove(function(e) {
		var ofsCanvas = $canvas.offset();
		var cw = $canvas.width();
		var ch = $canvas.height();
		var info = { left: e.pageX - ofsCanvas.left, top: e.pageY - ofsCanvas.top };
		var pos = {
			x: (viewport.x + (viewport.width * info.left / cw)),
			y: (viewport.y + (viewport.height * info.top / ch))
		}
		var func = $canvas.data('positionchange');
		if(func)
			func(pos);
	});
	var mouseupFunc = function() {
		$(window).unbind('mousemove', mousemoveFunc).unbind('mouseup', mouseupFunc);
		var ofsZoner = $zoner.offset();
		var ofsCanvas = $canvas.offset();
		var cw = $canvas.width();
		var ch = $canvas.height();
		var info = { left: ofsZoner.left - ofsCanvas.left, top: ofsZoner.top - ofsCanvas.top, width: $zoner.width(), height: $zoner.height() };
		var newViewport = {
			x: (viewport.x + (viewport.width * info.left / cw)),
			y: (viewport.y + (viewport.height * info.top / ch)),
			width: (viewport.width * (info.width / cw)),
			height: (viewport.height * (info.height / ch))
		};
		viewport = newViewport;
		$zoner.hide();
		drawView();
		$('body').removeClass('noselect');
	};
	var mousemoveFunc = function(e) {
		var ofs = {left: e.pageX, top: e.pageY};
		var ox, oy, w, h;
		var wx = false, hy = false;
		var ofsCanvas = $canvas.offset();
		var cw = $canvas.width();
		var ch = $canvas.height();
		if(ofs.left < ofsCanvas.left || ofs.top < ofsCanvas.top || ofs.left > (ofsCanvas.left + cw) || ofs.top > (ofsCanvas.top + ch))
			return;
		if(ofs.left < mousedownOfs.left) {
			ox = ofs.left;
			w = mousedownOfs.left - ox;
			wx = true;
		} else {
			ox = mousedownOfs.left;
			w = ofs.left - ox;
		}
		if(ofs.top < mousedownOfs.top) {
			oy = ofs.top;
			h = mousedownOfs.top - oy;
			hy = true;
		} else {
			oy = mousedownOfs.top;
			h = ofs.top - oy;
		}
		if(h * ratio > w) {
			h = parseInt(w / ratio);
			if(hy)
				oy = mousedownOfs.top - h;
		} else if(h * ratio < w) {
			w = parseInt(h * ratio);
			if(wx)
				ox = mousedownOfs.left - w;
		}
		$zoner.offset({left: ox, top: oy}).width(w).height(h);
	};

	var img = c.createImageData(width, height);

	var colorRanges = [
		{r: 0, g: 0, b: 0.25},
		{r: 0.75, g: 0.75, b: 0.75},
		{r: 0.9, g: 0.9, b: 0.9},
		{r: 1, g: 1, b: 1},
		{r: 0, g: 0, b: 0},
	];
	var drawView = function() {
		var x = 0, y = 0;
		var max = 400;
		for(;x<width;x++) {
			for(y = 0;y<height;y++) {
				var iter = getIterations(
					((x / width) * viewport.width) + viewport.x,
					((y / height) * viewport.height) + viewport.y,
					max
				);
				var idx = parseInt(iter * (colorRanges.length - 2) / max);
				var div = parseInt(max / (colorRanges.length - 1));
				var pct = (iter % div) / div;
				if(iter == max)
					pct = 1;
				var apct = 1 - pct;
				var r = (colorRanges[idx].r * apct + colorRanges[idx + 1].r * pct) * 255;
				var g = (colorRanges[idx].g * apct + colorRanges[idx + 1].g * pct) * 255;
				var b = (colorRanges[idx].b * apct + colorRanges[idx + 1].b * pct) * 255;
				setPixel(img, x, y, r, g, b, 255);
				/* black and white
				var rgb = parseInt((iter / max) * 256);
				if(rgb > 255)
					rgb = 255;
				setPixel(img, x, y, rgb, rgb, rgb, 255);
				*/
			}
		}
		c.putImageData(img, 0, 0);
	};

	drawView();

	$canvas.data('resetViewport', function() {
		viewport = { x: -3, y: -1, width: 4, height: 2 };
		drawView();
	});

");
		}
	}
}
